﻿using Microsoft.Extensions.Logging;

using PLCS.Application.Contracts.ProcessApp;
using PLCS.Application.Contracts.ProcessApp.Dtos;
using PLCS.Domain.Processes;
using PLCS.Shared.Common.Constant;
using PLCS.Shared.Common.Extensions;

using System.ComponentModel;
using System.Reflection;

using Volo.Abp.Application.Dtos;

namespace PLCS.Application.ProcessApp;

public class ProcessAppService : CrudAppService<Process, ProcessDto, Guid, PagedResultRequestDto, ProcessEditDto>, IProcessAppService
{
    private readonly IProcessRepository _processRepository;
    private readonly ILogger<ProcessAppService> _logger;

    public ProcessAppService(IProcessRepository processRepository, ILogger<ProcessAppService> logger) : base(processRepository)
    {
        _processRepository = processRepository;
        _logger = logger;
    }

    public override async Task<ProcessDto> CreateAsync(ProcessEditDto input)
    {
        var process = new Process(input.ProcessNo, input.ProcessName, input.TargetPos, isEnd: input.IsEnd, input.ContinueProcess);
        if (input.Triggers != null && input.Triggers.Count > 0)
        {
            foreach (var item in input.Triggers)
            {
                var trigger = await _processRepository.FindTriggerAsync(x => x.BackDataKey == item.BackDataKey
                && x.BackDataPath == item.BackDataPath
                && x.ComparisonType == item.ComparisonType
                && x.CompareValue == item.CompareValue);
                if (trigger == null)
                    trigger = await _processRepository.InsertTriggerAsync(
                        new Trigger(item.BackDataKey, item.BackDataPath, item.ComparisonType, item.CompareValue));

                process.AddTrigger(trigger);
            }
        }

        var entity = await _processRepository.InsertAsync(process);
        return await MapToGetOutputDtoAsync(entity);
    }

    public async Task<IEnumerable<ProcessDto>> GetProcessListAsync()
    {
        var processes = (await _processRepository.GetListAsync()).OrderByDescending(x => x.CreationTime);
        foreach (var item in processes)
        {
            // 找触发条件
            if (!string.IsNullOrEmpty(item.TriggerStrings))
            {
                if (item.Triggers == null)
                    item.Triggers = new List<Trigger>();
                foreach (var sonItem in item.TriggerStrings.Split(ConstantChar.SplitChar))
                {
                    var trigger = await _processRepository.FindTriggerAsync(x => x.Id.ToString() == sonItem);
                    if (trigger == null) continue;
                    item.Triggers.Add(trigger);
                }
            }
        }
        return ObjectMapper.Map<IEnumerable<Process>, IEnumerable<ProcessDto>>(processes);
    }

    public async Task<IEnumerable<TableDto>> GetTableNamesAsync()
    {
        List<TableDto> tableDtos = new List<TableDto>();

        Assembly assembly = Assembly.Load("ZFGG_JTX_PLCS.Domain");
        var res = assembly.GetTypes();
        Type[] types = assembly.GetTypes();
        var props = types.Where(x => x.Namespace == "ZFGG_JTX_PLCS.Domain.Entities");
        foreach (var item in props)
        {
            var attribute = item.GetCustomAttribute(typeof(DescriptionAttribute));
            if (attribute != null)
            {
                var tableDto = new TableDto()
                {
                    Description = /*(attribute as DescriptionAttribute).Description*/item.Name,
                    FiledName = item.Name,
                    TableName = $"T_{item.Name.ToPlural<string>()}",
                    Properties = new List<PropertyDto>()
                };
                foreach (var propItem in item.GetProperties())
                {
                    var propAttribute = propItem.GetCustomAttribute(typeof(DescriptionAttribute));
                    if (propAttribute != null)
                    {
                        tableDto.Properties.Add(new PropertyDto()
                        {
                            FieldName = propItem.Name,
                            Description = /*(propAttribute as DescriptionAttribute).Description*/propItem.Name,
                        });
                    }
                }
                tableDtos.Add(tableDto);
            }
        }
        await Task.Delay(1);

        return tableDtos;
    }

    public async Task UpdateAsync(ProcessEditDto input)
    {
        var process = await _processRepository.FindAsync(input.Id);
        if (process == null)
            throw new Exception("工序不存在");
        process.ProcessName = input.ProcessName;
        process.TargetPos = input.TargetPos;
        process.ContinueProcess = input.ContinueProcess;
        process.TriggerStrings = string.Empty;
        process.IsEnd = input.IsEnd;
        process.WorkStepStrings = string.Empty;
        if (input.Triggers != null && input.Triggers.Count > 0)
        {
            foreach (var item in input.Triggers)
            {
                var trigger = await _processRepository.FindTriggerAsync(x => x.BackDataKey == item.BackDataKey
                && x.BackDataPath == item.BackDataPath
                && x.ComparisonType == item.ComparisonType
                && x.CompareValue == item.CompareValue);
                if (trigger == null)
                    trigger = await _processRepository.InsertTriggerAsync(
                        new Trigger(item.BackDataKey, item.BackDataPath, item.ComparisonType, item.CompareValue));

                process.AddTrigger(trigger);
            }
        }
        if (process.TriggerStrings.IsNullOrEmpty() && process.IsTrigger)
            process.IsTrigger = false;

        await _processRepository.UpdateAsync(process); ;
    }

    public async Task<ProcessDto> GetByProcessNoAsync(string processNo)
    {
        var entity = await _processRepository.FindProcessByNoAsync(processNo);
        Check.NotNull(entity, processNo);
        return ObjectMapper.Map<Process, ProcessDto>(entity);
    }

    public async Task<PagedResultDto<ProcessDto>> GetListBySearchAsync(PagedResultRequestDto input, string? processNo)
    {
        await CheckGetListPolicyAsync();

        var query = await CreateFilteredQueryAsync(input);
        query = query.WhereIf(!string.IsNullOrEmpty(processNo), x => x.ProcessNo == processNo);
        var totalCount = await AsyncExecuter.CountAsync(query);

        query = ApplyPaging(query, input);

        var entities = await AsyncExecuter.ToListAsync(query);
        foreach (var entity in entities)
        {
            if (string.IsNullOrEmpty(entity.TriggerStrings))
                continue;
            foreach (var item in entity.TriggerStrings.Split(ConstantChar.SplitChar))
            {
                entity.Triggers ??= new List<Trigger>();
                entity.Triggers.Add(await _processRepository.FindTriggerAsync(x => x.Id == Guid.Parse(item)));
            }
        }
        var entityDtos = await MapToGetListOutputDtosAsync(entities);

        return new PagedResultDto<ProcessDto>(
            totalCount,
            entityDtos
        );
    }
}